import { CurCanvas, GetGL } from "./gp/gl";
import Sprite from "./gp/sprite";
import { Shader } from "./gp/shader";
import { ShaderValueType } from "./gp/shader";
var billiardsVS = `
attribute vec4 posuv;
attribute float ballNum;
attribute vec3 m1;
attribute vec3 m2;
attribute vec3 m3;
uniform vec2 size;	
varying vec2 uv;
varying mat3 m;
varying float num;
varying vec4 ballColor;
void main() {
    vec4 pos = vec4(posuv.xy,0.,1.);
    vec4 pos1  =vec4((pos.x/size.x-0.5)*2.0,(0.5-pos.y/size.y)*2.0,0.,1.0);
    gl_Position=pos1;
    uv = posuv.zw;
    m = mat3(m1.x, m1.y, m1.z, m2.x, m2.y, m2.z, m3.x, m3.y, m3.z);
    num = ballNum;
    float colorNum = num;
    if (colorNum > 8.5) {
        colorNum -= 8.0;
    }
    if (colorNum <0.5) {
        ballColor = vec4(0.9, 0.9, 0.9, 1.0);
    } else if (colorNum <1.5) {
        ballColor = vec4(1.0, 0.831, 0.0, 1.);
    } else if (colorNum <2.5) {
        ballColor = vec4(0.1058, 0.278, 0.753, 1.0);
    } else if (colorNum <3.5) {
        ballColor = vec4(0.9137254901960784,0.19607843137254902,0.03529411764705882, 1.0);
    } else if (colorNum <4.5) {
        ballColor = vec4(0.27450980392156865,0.16470588235294117,0.5372549019607843, 1.0);
    } else if (colorNum <5.5) {
        ballColor = vec4(1.0,0.6431372549019608,0.11764705882352941, 1.0);
    } else if (colorNum <6.5) {
        ballColor = vec4(0.0,0.3764705882352941,0.36470588235294116, 1.0);
    } else if (colorNum <7.5) {
        ballColor = vec4(0.5333333333333333,0.06274509803921569,0.043137254901960784, 1.0);
    } else if (colorNum < 200.0) {
        ballColor = vec4(1.,0.,0., 1.);
    }
}`;

var billiardsPS = `
#if defined(GL_FRAGMENT_PRECISION_HIGH)
precision highp float;
#else
precision mediump float;
#endif
varying vec2 uv;
uniform sampler2D texture;
uniform vec2 size;
const float cx = 0.5;
const float cy = 0.5;
varying mat3 m;
varying float num;
varying vec4 ballColor;
const float bp = 0.55;
const float whiteLen = 0.9;
void main() {
    vec4 color= ballColor;
    float du = (uv.x - cx);
    float dv = (uv.y - cy);

    // 球面坐标
    float x = du * 2.0;
    float y = dv * 2.0;
    float z = sqrt(1.0 - x * x - y * y);

    // 逆矩阵算出正面时的坐标
    vec3 p3d = vec3(x, y, z);
    p3d = m * p3d;
    
    if (num > 8.5) {

        // 上下两个白圈的中心店
        vec3 white1 = vec3(0.0, 1.0, 0.0);
        vec3 white2 = vec3(0.0, -1.0, 0.0);

        vec3 dw1 = white1 - p3d;
        vec3 dw2 = white2 - p3d;
        // 判断距离
        if (length(dw1) < whiteLen || length(dw2) < whiteLen) {
            color = vec4(1.0, 1.0, 1.0, 1.0);
        }

    }
    vec3 dnum = p3d - vec3(0.0, 0.0, 1.0);
    if (num > 0.5 && length(dnum) < bp) {
        vec4 t_color = texture2D(texture, vec2(dnum.x + cx, dnum.y + cy));
        color.rgb = ballColor.rgb * (1.0 - t_color.a) + t_color.rgb * ballColor.a;
        color.a = 1.0;
    }
    if (num < 0.5) {
        vec3 red1 = vec3(0.0, 0.707, 0.707);
        vec3 red2 = vec3(0.5, -0.5, 0.707);
        vec3 red3 = vec3(-0.5, -0.5, 0.707);

        vec3 dred1 = p3d - red1;
        vec3 dred2 = p3d - red2;
        vec3 dred3 = p3d - red3;
        if (length(dred1) < 0.2 || length(dred2) < 0.2 || length(dred3) < 0.2) {
            color = vec4(1.0, 0.0, 0.0, 1.0);
        }
    }     
    if (du * du + dv * dv > 0.25) {
        color = vec4(0., 0., 0., 0.);
    }

    gl_FragColor=color;
}
`;
export default class Billiards extends Sprite {
    num = 0;
    mat = [
        1, 0, 0,
        0, 1, 0,
        0, 0, 1
    ];
    scrollSpeed = 0;
    scrollAxis = { x: 1, y: 0, z: 0 };
    constructor(num) {
        super("res/ballNum/" + (num ? num : 1) + ".png");
        this.num = num;
    }
    set texture(texture) {
        this._texture = texture;
        if (!this.shader)
            this.shader = createBilliardsShader(this.num, texture);
    }
    scroll(rad, x, y, z) {

        // 矩阵旋转
        // 传入的是逆矩阵，所以计算反向旋转
        // 因为只需要计算3d旋转，所以用3x3矩阵表示
        const s = Math.sin(-rad);
        const c = Math.cos(-rad);
        const t = 1 - c;


        let a = this.mat;
        const a00 = a[0]; const a01 = a[1]; const a02 = a[2];
        const a10 = a[3]; const a11 = a[4]; const a12 = a[5];
        const a20 = a[6]; const a21 = a[7]; const a22 = a[8];

        const b00 = x * x * t + c; const b01 = y * x * t + z * s; const b02 = z * x * t - y * s;
        const b10 = x * y * t - z * s; const b11 = y * y * t + c; const b12 = z * y * t + x * s;
        const b20 = x * z * t + y * s; const b21 = y * z * t - x * s; const b22 = z * z * t + c;

        a[0] = a00 * b00 + a10 * b01 + a20 * b02;
        a[1] = a01 * b00 + a11 * b01 + a21 * b02;
        a[2] = a02 * b00 + a12 * b01 + a22 * b02;

        a[3] = a00 * b10 + a10 * b11 + a20 * b12;
        a[4] = a01 * b10 + a11 * b11 + a21 * b12;
        a[5] = a02 * b10 + a12 * b11 + a22 * b12;

        a[6] = a00 * b20 + a10 * b21 + a20 * b22;
        a[7] = a01 * b20 + a11 * b21 + a21 * b22;
        a[8] = a02 * b20 + a12 * b21 + a22 * b22;

    }
    getVertices() {
        let x = this.x;
        let y = this.y;
        let ax = this.anchorX;
        let ay = this.anchorY;
        let w = this.width;
        let h = this.height;

        let x1 = x - w * ax;
        let x2 = x + w * (1 - ax);
        let y1 = y - h * ay;
        let y2 = y + h * (1 - ay);

        let posuv = [
            [x1, y1, 0, 1],
            [x2, y1, 1, 1],
            [x2, y2, 1, 0],
            [x2, y2, 1, 0],
            [x1, y2, 0, 0],
            [x1, y1, 0, 1],
        ];

        let vertices = [];
        for (let i = 0; i < posuv.length; i++) {
            vertices.push(posuv[i][0]);
            vertices.push(posuv[i][1]);
            vertices.push(posuv[i][2]);
            vertices.push(posuv[i][3]);
            vertices.push(this.num);
            for (let t = 0; t < 9; t++) {
                vertices.push(this.mat[t]);
            }
        }
        return vertices;
    }
    update(dt) {
        let rad = dt * this.scrollSpeed;
        this.scroll(rad, this.scrollAxis.x, this.scrollAxis.y, this.scrollAxis.z);
    }
}

let BilliardsShaders = {};
var createBilliardsShader = function (num, texture) {
    if (!BilliardsShaders[texture.src]) {
        let canvas = CurCanvas();
        let shader = new Shader(billiardsVS, billiardsPS);
        shader.setValue("size", {
            type: ShaderValueType.Vec2,
            value: [canvas.width, canvas.height]
        });
        shader.setValue('texture', {
            type: ShaderValueType.Texture,
            index: 0,
            value: texture
        });
        let gl = GetGL();
        shader.setAttributes([
            ["posuv", 4, gl.FLOAT],
            ["ballNum", 1, gl.FLOAT],
            ["m1", 3, gl.FLOAT],
            ["m2", 3, gl.FLOAT],
            ["m3", 3, gl.FLOAT],
        ]);
        BilliardsShaders[texture.src] = shader;
    }
    return BilliardsShaders[texture.src];
};